package org.carl.akka.service;

import akka.actor.ActorRef;
import lombok.extern.slf4j.Slf4j;
import org.carl.akka.base.BaseAkkaActor;
import org.carl.akka.core.AkkaCore;
import scala.concurrent.duration.FiniteDuration;

import java.time.Duration;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;

// 使用@Slf4j注解，以便在类中使用日志记录功能
@Slf4j
public class AkkaService implements AkkaCore {

    /**
     * 向指定的Actor发送消息
     *
     * @param clazz   消息接收者Actor的类
     * @param message 要发送的消息对象
     * @param sender  发送者的ActorRef，如果为null，则使用ActorRef.noSender()
     */
    public void tell(Class<? extends BaseAkkaActor> clazz, Object message, ActorRef sender) {
        // 尝试从ACTOR_REF_MAP中获取与clazz对应的ActorRef
        Optional.ofNullable(ACTOR_REF_MAP.get(clazz)).ifPresentOrElse(
                // 如果找到了ActorRef，则向该Actor发送消息
                actorRef -> actorRef.tell(message, Objects.isNull(sender) ? ActorRef.noSender() : sender),
                // 如果没有找到ActorRef，则记录错误日志
                () -> log.error("ACTOR_REF_MAP中未找到{}对应的ActorRef", clazz)
        );
    }

    /**
     * 在指定的延迟后发送消息给指定的Actor
     *
     * @param clazz   消息接收者Actor的类
     * @param message 要发送的消息对象
     * @param sender  发送者的ActorRef，如果为null，则使用ActorRef.noSender()
     * @param delay   延迟时间
     */
    public void scheduleOnce(Class<? extends BaseAkkaActor> clazz, Object message, ActorRef sender, FiniteDuration delay) {
        // 获取ActorSystem的调度器实例，并安排一个任务在指定延迟后执行
        ACTOR_SYSTEM.get().scheduler().scheduleOnce(
                delay, // 延迟时间
                () -> tell(clazz, message, sender), // 延迟后要执行的任务
                ACTOR_SYSTEM.get().dispatcher() // 任务执行的调度器上下文
        );
    }

    /**
     * 向指定的Actor发送消息，并等待响应
     *
     * @param clazz   消息接收者Actor的类
     * @param message 要发送的消息对象
     * @return 一个CompletionStage对象，它将在收到响应时完成，并包含响应对象
     */
    public CompletionStage<Object> ask(Class<? extends BaseAkkaActor> clazz, Object message, Duration delay) {
        // 从ACTOR_REF_MAP中获取与clazz对应的ActorRef
        Optional<ActorRef> actorRefOptional = Optional.ofNullable(ACTOR_REF_MAP.get(clazz));
        if (actorRefOptional.isPresent()) {
            ActorRef actorRef = actorRefOptional.get();
            // 使用ActorSystem的ask方法来发送消息并等待响应
            return akka.pattern.Patterns.ask(actorRef, message, delay);
        } else {
            log.error("ACTOR_REF_MAP中未找到{}对应的ActorRef", clazz);
            return CompletableFuture.completedFuture(null);
        }
        // 这里仅提供一个示例性的注释，具体实现取决于项目需求
    }
}